package com.ssy.lingxi.member.merchant.serviceimpl.web;

import cn.hutool.core.util.StrUtil;
import com.ssy.lingxi.common.constant.Constants;
import com.ssy.lingxi.common.constant.basic.EnableDisableStatus;
import com.ssy.lingxi.common.constant.basic.UserLoginSourceEnum;
import com.ssy.lingxi.common.constant.member.MemberLevelTypeEnum;
import com.ssy.lingxi.common.constant.member.MemberStatusEnum;
import com.ssy.lingxi.common.constant.member.MemberTypeEnum;
import com.ssy.lingxi.common.constant.member.RoleTypeEnum;
import com.ssy.lingxi.common.model.dto.MemberAndRoleIdDTO;
import com.ssy.lingxi.common.model.dto.UserLoginCacheDTO;
import com.ssy.lingxi.common.response.ResponseCode;
import com.ssy.lingxi.common.response.Wrapper;
import com.ssy.lingxi.common.utils.PasswordUtil;
import com.ssy.lingxi.common.utils.TokenUtil;
import com.ssy.lingxi.component.redis.service.IRedisUtils;
import com.ssy.lingxi.member.merchant.api.constant.MemberRelationTypeEnum;
import com.ssy.lingxi.member.merchant.config.ServiceConfig;
import com.ssy.lingxi.member.merchant.config.ServiceVariable;
import com.ssy.lingxi.member.merchant.entity.*;
import com.ssy.lingxi.member.merchant.model.bo.*;
import com.ssy.lingxi.member.merchant.model.constant.MemberOuterStatusEnum;
import com.ssy.lingxi.member.merchant.model.constant.MemberValidateStatusEnum;
import com.ssy.lingxi.member.merchant.model.vo.login.request.*;
import com.ssy.lingxi.member.merchant.model.vo.login.response.CaptchaPicVO;
import com.ssy.lingxi.member.merchant.model.vo.login.response.MemberAuthCodeVO;
import com.ssy.lingxi.member.merchant.repository.MemberRelationRepository;
import com.ssy.lingxi.member.merchant.repository.MemberRepository;
import com.ssy.lingxi.member.merchant.repository.MemberUserRepository;
import com.ssy.lingxi.member.merchant.service.base.IBaseMemberCacheService;
import com.ssy.lingxi.member.merchant.service.base.IBaseMemberCreditAsyncService;
import com.ssy.lingxi.member.merchant.service.base.IBaseMemberLevelAsyncService;
import com.ssy.lingxi.member.merchant.service.web.IMemberLoginService;
import com.ssy.lingxi.member.merchant.utils.AuthBOUtils;
import com.ssy.lingxi.member.merchant.utils.MemberOrganizationUtil;
import com.ssy.lingxi.member.merchant.utils.VerifyImageUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.http.HttpHeaders;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import javax.persistence.criteria.Join;
import javax.persistence.criteria.JoinType;
import javax.persistence.criteria.Predicate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * Web客户端、平台后台用户登录服务接口
 *
 * @author 万宁
 * @version 2.0.0
 * @date 2020-06-05
 */
@Service
public class MemberLoginServiceImpl implements IMemberLoginService {
    @Resource
    private MemberRepository memberRepository;

    @Resource
    private MemberUserRepository memberUserRepository;

    @Resource
    private MemberRelationRepository relationRepository;

    @Resource
    private IBaseMemberCacheService memberCacheService;

    @Resource
    private IBaseMemberLevelAsyncService baseMemberLevelAsyncService;

    @Resource
    private IBaseMemberCreditAsyncService baseMemberCreditAsyncService;

    @Resource
    private JdbcTemplate jdbcTemplate;

    @Autowired
    private IRedisUtils redisUtils;

    @Override
    public Wrapper<WebLoginBO> accountOrPhoneLogin(HttpHeaders headers, MemberLoginVO loginVO) {
        memberCacheService.checkWebRequestHeader(headers);

        MemberUserDO memberUserDO = memberUserRepository.findLoginUser(loginVO.getAccount(), loginVO.getAccount(), MemberRelationTypeEnum.OTHER.getCode());
        if (memberUserDO == null || memberUserDO.getStatus().equals(EnableDisableStatus.DISABLE.getCode())) {
            return Wrapper.fail(ResponseCode.USER_ACCOUNT_OR_PASSWORD_INCORRECT);
        }

        MemberDO memberDO = memberUserDO.getMember();
        if (memberDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_DOES_NOT_EXIST);
        }

        //校验密码
        if (!PasswordUtil.instance().checkPassword(memberUserDO.getPassword(), loginVO.getPassword())) {
            return Wrapper.fail(ResponseCode.USER_ACCOUNT_OR_PASSWORD_INCORRECT);
        }

        //登录会员上下级会员的关系列表
        Specification<MemberRelationDO> specification = (Specification<MemberRelationDO>) (root, query, criteriaBuilder) -> {
            List<Predicate> list = new ArrayList<>();
            list.add(criteriaBuilder.or(criteriaBuilder.equal(root.get("memberId").as(Long.class), memberDO.getId()), criteriaBuilder.equal(root.get("subMemberId").as(Long.class), memberDO.getId())));
            list.add(criteriaBuilder.or(criteriaBuilder.equal(root.get("relType").as(Integer.class), MemberRelationTypeEnum.PLATFORM.getCode()),
                    criteriaBuilder.and(criteriaBuilder.equal(root.get("relType").as(Integer.class), MemberRelationTypeEnum.OTHER.getCode()),
                            criteriaBuilder.equal(root.get("verified").as(Integer.class), MemberValidateStatusEnum.VERIFY_PASSED.getCode()),
                            criteriaBuilder.equal(root.get("status").as(Integer.class), MemberStatusEnum.NORMAL.getCode()))));
            Predicate[] p = new Predicate[list.size()];
            return criteriaBuilder.and(list.toArray(p));
        };

        List<MemberRelationDO> relationDOList = relationRepository.findAll(specification);
        if (CollectionUtils.isEmpty(relationDOList)) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_DOES_NOT_EXIST);
        }

        //从“平台会员”关系中，查询是否已经被冻结
        List<MemberRelationDO> platformRelationDOList = relationDOList.stream().filter(relationDO -> relationDO.getSubMemberId().equals(memberDO.getId()) && relationDO.getRelType().equals(MemberRelationTypeEnum.PLATFORM.getCode())).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(platformRelationDOList)) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_DOES_NOT_EXIST);
        }

        //如果所有平台关系已经被冻结，返回
        List<Long> unfrozenRoleIdList = platformRelationDOList.stream().filter(relationDO -> relationDO.getStatus().equals(MemberStatusEnum.NORMAL.getCode())).map(MemberRelationDO::getSubRoleId).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(unfrozenRoleIdList)) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_HAS_BEEN_FROZEN);
        }

        //筛选出未冻结、状态为启用的角色
        List<RoleDO> availableRoles = memberDO.getRoles().stream().filter(roleDO -> roleDO.getStatus().equals(EnableDisableStatus.ENABLE.getCode()) && unfrozenRoleIdList.contains(roleDO.getId())).sorted(Comparator.comparingLong(RoleDO::getId)).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(availableRoles)) {
            return Wrapper.fail(ResponseCode.MC_MS_ROLE_HAS_BEEN_DISABLED);
        }

        //会员所有角色
        String roleNames = availableRoles.stream().map(RoleDO::getRoleName).collect(Collectors.joining(","));

        //登录的角色
        RoleDO roleDO = availableRoles.get(0);
        List<WebLoginBO.MemberRoleItem> roleItemList = availableRoles.stream().map(r -> {
            WebLoginBO.MemberRoleItem item = new WebLoginBO.MemberRoleItem();
            item.setMemberRoleId(r.getId());
            item.setMemberRoleName(r.getRoleName());
            item.setRoleType(r.getRoleType().getTypeEnum());
            return item;
        }).collect(Collectors.toList());

        //登录的平台会员关系
        MemberRelationDO loginPlatformRelationDO = relationDOList.stream().filter(relationDO -> relationDO.getSubMemberId().equals(memberDO.getId()) && relationDO.getSubRoleId().equals(roleDO.getId()) && relationDO.getRelType().equals(MemberRelationTypeEnum.PLATFORM.getCode())).findFirst().orElse(null);
        if (loginPlatformRelationDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_RELATION_DOES_NOT_EXIST);
        }

        //审核状态（如果审核状态为不通过，找到审核不通过的原因）
        Integer validateStatus = loginPlatformRelationDO.getOuterStatus();
        String validateStatusDesc = MemberOuterStatusEnum.getCodeMsg(validateStatus);
        String validateMsg = "";
        if (validateStatus.equals(MemberOuterStatusEnum.PLATFORM_VERIFY_NOT_PASSED.getCode())) {
            validateMsg = StringUtils.hasLength(loginPlatformRelationDO.getValidateMsg()) ? loginPlatformRelationDO.getValidateMsg() : "";
        }

        Integer level = loginPlatformRelationDO.getLevelRight().getLevel();
        String levelTag = loginPlatformRelationDO.getLevelRight().getLevelTag();
        Integer score = loginPlatformRelationDO.getLevelRight().getScore();
        Integer creditPoint = loginPlatformRelationDO.getCredit().getCreditPoint();
        String logo = StringUtils.hasLength(memberUserDO.getLogo()) ? memberUserDO.getLogo() : "";
        Long orgId = memberUserDO.getOrg() == null ? 0L : memberUserDO.getOrg().getId();
        List<MemberOrganizationDO> orgList = new ArrayList<>(memberDO.getOrgs());
        String orgName = MemberOrganizationUtil.joinTitleToString(orgId, orgList);


        String token;
        try {
            token = TokenUtil.instance().getToken();
        } catch (Exception e) {
            return Wrapper.fail(ResponseCode.SERVICE_ERROR);
        }

        //授权访问的前端菜单Url列表，如果审核没通过，只能访问首页
        //List<String> urlList = loginPlatformRelationDO.getVerified().equals(MemberValidateStatusEnum.VERIFY_PASSED.getCode()) ? AuthBOUtils.getAccessUrlList(memberUserDO.getUserAuth().getAuth(), loginPlatformRelationDO.getRelationAuth().getAuth(), UserLoginSourceEnum.BUSINESS_WEB.getCode(), ServiceConfig.MEMBER_MAIN_WEB_PAGE_CODES) : ServiceConfig.MEMBER_MAIN_WEB_PAGE_CODES;
        List<String> urlList = new ArrayList<>();
        List<LoginAuthBO> auth = AuthBOUtils.getAccessAuth(loginPlatformRelationDO.getVerified().equals(MemberValidateStatusEnum.VERIFY_PASSED.getCode()), memberUserDO.getUserAuth().getAuth(), loginPlatformRelationDO.getRelationAuth().getAuth(), UserLoginSourceEnum.BUSINESS_WEB.getCode(), ServiceConfig.MEMBER_MAIN_WEB_PAGE_CODES);

        //上级渠道会员的Id列表
        List<Long> upperChannelMemberIds = relationDOList.stream().filter(relationDO -> relationDO.getSubMemberId().equals(memberDO.getId()) && relationDO.getSubRoleId().equals(roleDO.getId()) && relationDO.getRelType().equals(MemberRelationTypeEnum.OTHER.getCode()) && relationDO.getRole().getMemberType().getTypeEnum().equals(MemberTypeEnum.CHANNEL.getCode()) || relationDO.getRole().getMemberType().getTypeEnum().equals(MemberTypeEnum.CHANNEL_PERSONAL.getCode())).map(MemberRelationDO::getMemberId).distinct().collect(Collectors.toList());

        //上级供应商
        List<MemberAndRoleIdDTO> upperVendorMembers = roleDO.getRoleType().getTypeEnum().equals(RoleTypeEnum.SERVICE_PROVIDER.getCode()) ? relationDOList.stream().filter(relationDO -> relationDO.getSubMemberId().equals(memberDO.getId()) && relationDO.getSubRoleId().equals(roleDO.getId()) && relationDO.getRelType().equals(MemberRelationTypeEnum.OTHER.getCode()) && relationDO.getRole().getRoleType().getTypeEnum().equals(RoleTypeEnum.SERVICE_PROVIDER.getCode())).map(relationDO -> new MemberAndRoleIdDTO(relationDO.getMemberId(), relationDO.getRoleId())).collect(Collectors.toList()) : new ArrayList<>();

        //下级供应商
        List<MemberAndRoleIdDTO> subVendorMembers = roleDO.getRoleType().getTypeEnum().equals(RoleTypeEnum.SERVICE_PROVIDER.getCode()) ? relationDOList.stream().filter(relationDO -> relationDO.getMemberId().equals(memberDO.getId()) && relationDO.getRoleId().equals(roleDO.getId()) && relationDO.getRelType().equals(MemberRelationTypeEnum.OTHER.getCode()) && relationDO.getSubRole().getRoleType().getTypeEnum().equals(RoleTypeEnum.SERVICE_PROVIDER.getCode())).map(relationDO -> new MemberAndRoleIdDTO(relationDO.getSubMemberId(), relationDO.getSubRoleId())).collect(Collectors.toList()) : new ArrayList<>();

        //下级渠道会员Id和角色Id列表
        List<MemberRelationDO> subChannelRelationDOList = relationDOList.stream().filter(relationDO -> relationDO.getMemberId().equals(memberDO.getId()) && relationDO.getRoleId().equals(roleDO.getId()) && relationDO.getRelType().equals(MemberRelationTypeEnum.OTHER.getCode())).collect(Collectors.toList());
        List<MemberAndRoleIdDTO> subChannelMembers = subChannelRelationDOList.stream().filter(relationDO -> relationDO.getSubRole().getMemberType().getTypeEnum().equals(MemberTypeEnum.CHANNEL.getCode()) || relationDO.getSubRole().getMemberType().getTypeEnum().equals(MemberTypeEnum.CHANNEL_PERSONAL.getCode())).map(relationDO -> new MemberAndRoleIdDTO(relationDO.getSubMemberId(), relationDO.getSubRoleId())).collect(Collectors.toList());

        // 根据当前登录角色判断等级类型
        Integer memberLevelTypeEnum = MemberLevelTypeEnum.getCodeByMemberType(roleDO.getMemberType().getTypeEnum());

        Long siteId = memberCacheService.getLongValueFromRequestHeader(headers, ServiceConfig.USER_LOGIN_SITE_HTTP_HEADERS_KEY);
        Long shopId = memberCacheService.getLongValueFromRequestHeader(headers, ServiceConfig.USER_LOGIN_SHOP_HTTP_HEADERS_KEY);

        //缓存用户信息
        memberCacheService.cacheUserInfo(UserLoginSourceEnum.BUSINESS_WEB, memberLevelTypeEnum, memberUserDO, memberDO, roleDO, upperChannelMemberIds, upperVendorMembers, subVendorMembers, subChannelMembers, new ArrayList<>(), token, siteId, shopId,level);

        //返回结果
        WebLoginBO webLoginBO = new WebLoginBO(memberUserDO.getId(), memberDO.getId(), token, memberUserDO.getAccount(), memberDO.getName(), memberUserDO.getName(), ServiceVariable.WEB_LOGIN_TOKEN_EXPIRE_MINUTES, urlList, auth, roleDO.getId(), roleDO.getMemberType().getTypeEnum(), roleDO.getRoleType().getTypeEnum(), roleNames, validateStatus, validateStatusDesc, validateMsg, level, levelTag, score, creditPoint, logo, roleItemList, orgId, orgName);

        //异步： 计算会员登录获得的积分、会员注册年限获得的信用积分
        baseMemberLevelAsyncService.calculateMemberLoginScore(loginPlatformRelationDO, UserLoginSourceEnum.BUSINESS_WEB.getCode());

        baseMemberCreditAsyncService.calculateMemberRegisterYearsCredit(relationDOList.stream().filter(relationDO -> relationDO.getSubMemberId().equals(memberDO.getId()) && relationDO.getSubRoleId().equals(roleDO.getId())).collect(Collectors.toList()));

        //记录最后一次登录时间
        updateUserLastLoginTimeAsync(memberUserDO.getId());

        return Wrapper.success(webLoginBO);
    }


    /**
     * 业务平台 - 切换登录用户的会员角色
     *
     * @param headers HttpHeaders信息
     * @param roleVO  接口参数
     * @return 操作结果
     */
    @Override
    public Wrapper<WebLoginBO> switchMemberRole(HttpHeaders headers, MemberLoginSwitchMemberRoleVO roleVO) {
        UserLoginCacheDTO loginUser = memberCacheService.checkUserFromCache(headers);
        String oldToken = headers.getFirst(ServiceConfig.USER_TOKEN_HTTP_HEADERS_KEY);

        //从数据库中读取用户信息
        MemberUserDO memberUserDO = memberUserRepository.findById(loginUser.getUserId()).orElse(null);
        if (memberUserDO == null || memberUserDO.getStatus().equals(EnableDisableStatus.DISABLE.getCode())) {
            return Wrapper.fail(ResponseCode.USER_ACCOUNT_OR_PASSWORD_INCORRECT);
        }

        MemberDO memberDO = memberUserDO.getMember();
        if (memberDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_DOES_NOT_EXIST);
        }

        //会员关系列表
        Specification<MemberRelationDO> specification = (Specification<MemberRelationDO>) (root, query, criteriaBuilder) -> {
            List<Predicate> list = new ArrayList<>();
            list.add(criteriaBuilder.or(criteriaBuilder.equal(root.get("memberId").as(Long.class), memberDO.getId()), criteriaBuilder.equal(root.get("subMemberId").as(Long.class), memberDO.getId())));
            list.add(criteriaBuilder.or(criteriaBuilder.equal(root.get("relType").as(Integer.class), MemberRelationTypeEnum.PLATFORM.getCode()),
                    criteriaBuilder.and(criteriaBuilder.equal(root.get("relType").as(Integer.class), MemberRelationTypeEnum.OTHER.getCode()),
                            criteriaBuilder.equal(root.get("verified").as(Integer.class), MemberValidateStatusEnum.VERIFY_PASSED.getCode()),
                            criteriaBuilder.equal(root.get("status").as(Integer.class), MemberStatusEnum.NORMAL.getCode()))));
            Predicate[] p = new Predicate[list.size()];
            return criteriaBuilder.and(list.toArray(p));
        };

        List<MemberRelationDO> relationDOList = relationRepository.findAll(specification);
        if (CollectionUtils.isEmpty(relationDOList)) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_DOES_NOT_EXIST);
        }

        //从“平台会员”关系中，查询是否已经被冻结
        List<MemberRelationDO> platformRelationDOList = relationDOList.stream().filter(relationDO -> relationDO.getSubMemberId().equals(memberDO.getId()) && relationDO.getRelType().equals(MemberRelationTypeEnum.PLATFORM.getCode())).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(platformRelationDOList) || platformRelationDOList.stream().noneMatch(relationDO -> relationDO.getSubRoleId().equals(roleVO.getMemberRoleId()))) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_DOES_NOT_EXIST);
        }

        List<Long> unfrozenRoleIdList = platformRelationDOList.stream().filter(relationDO -> relationDO.getStatus().equals(MemberStatusEnum.NORMAL.getCode())).map(MemberRelationDO::getSubRoleId).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(unfrozenRoleIdList) || !unfrozenRoleIdList.contains(roleVO.getMemberRoleId())) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_HAS_BEEN_FROZEN);
        }

        //筛选出未冻结，且状态为启用的角色
        List<RoleDO> availableRoles = memberDO.getRoles().stream().filter(roleDO -> roleDO.getStatus().equals(EnableDisableStatus.ENABLE.getCode()) && unfrozenRoleIdList.contains(roleDO.getId())).sorted(Comparator.comparingLong(RoleDO::getId)).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(availableRoles) || availableRoles.stream().noneMatch(role -> role.getId().equals(roleVO.getMemberRoleId()))) {
            return Wrapper.fail(ResponseCode.MC_MS_ROLE_HAS_BEEN_DISABLED);
        }

        //找出要切换的角色
        RoleDO roleDO = availableRoles.stream().filter(r -> r.getId().equals(roleVO.getMemberRoleId())).findFirst().orElse(null);
        if (roleDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_ROLE_DOES_NOT_EXIST);
        }

        List<WebLoginBO.MemberRoleItem> roleItemList = availableRoles.stream().map(r -> {
            WebLoginBO.MemberRoleItem item = new WebLoginBO.MemberRoleItem();
            item.setMemberRoleId(r.getId());
            item.setMemberRoleName(r.getRoleName());
            item.setRoleType(r.getRoleType().getTypeEnum());
            return item;
        }).collect(Collectors.toList());

        //登录的平台会员关系
        MemberRelationDO loginPlatformRelationDO = relationDOList.stream().filter(relationDO -> relationDO.getSubMemberId().equals(memberDO.getId()) && relationDO.getSubRoleId().equals(roleDO.getId()) && relationDO.getRelType().equals(MemberRelationTypeEnum.PLATFORM.getCode())).findFirst().orElse(null);
        if (loginPlatformRelationDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_RELATION_DOES_NOT_EXIST);
        }

        //会员所有角色
        String roleNames = availableRoles.stream().map(RoleDO::getRoleName).collect(Collectors.joining(","));
        //审核状态（如果审核状态为不通过，找到审核不通过的原因）
        Integer validateStatus = loginPlatformRelationDO.getOuterStatus();
        String validateStatusDesc = MemberOuterStatusEnum.getCodeMsg(validateStatus);
        String validateMsg = "";
        if (validateStatus.equals(MemberOuterStatusEnum.PLATFORM_VERIFY_NOT_PASSED.getCode())) {
            validateMsg = StringUtils.hasLength(loginPlatformRelationDO.getValidateMsg()) ? loginPlatformRelationDO.getValidateMsg() : "";
        }

        Integer level = loginPlatformRelationDO.getLevelRight().getLevel();
        String levelTag = loginPlatformRelationDO.getLevelRight().getLevelTag();
        Integer score = loginPlatformRelationDO.getLevelRight().getScore();
        Integer creditPoint = loginPlatformRelationDO.getCredit().getCreditPoint();
        String logo = StringUtils.hasLength(memberUserDO.getLogo()) ? memberUserDO.getLogo() : "";

        //会员等级类型
        Integer memberLevelTypeEnum = MemberLevelTypeEnum.getCodeByMemberType(roleDO.getMemberType().getTypeEnum());

        String token = TokenUtil.instance().getToken();

        //删除旧Token
        memberCacheService.deleteUserToken(oldToken);

        //授权访问的前菜单Url列表
        //List<String> urlList = loginPlatformRelationDO.getVerified().equals(MemberValidateStatusEnum.VERIFY_PASSED.getCode()) ? AuthBOUtils.getAccessUrlList(memberUserDO.getUserAuth().getAuth(), loginPlatformRelationDO.getRelationAuth().getAuth(), UserLoginSourceEnum.BUSINESS_WEB.getCode(), ServiceConfig.MEMBER_MAIN_WEB_PAGE_CODES) : ServiceConfig.MEMBER_MAIN_WEB_PAGE_CODES;
        List<String> urlList = new ArrayList<>();
        List<LoginAuthBO> auth = AuthBOUtils.getAccessAuth(loginPlatformRelationDO.getVerified().equals(MemberValidateStatusEnum.VERIFY_PASSED.getCode()), memberUserDO.getUserAuth().getAuth(), loginPlatformRelationDO.getRelationAuth().getAuth(), UserLoginSourceEnum.BUSINESS_WEB.getCode(), ServiceConfig.MEMBER_MAIN_WEB_PAGE_CODES);

        //上级渠道会员的Id列表
        List<MemberRelationDO> upperChannelRelationDOList = relationDOList.stream().filter(relationDO -> relationDO.getSubMemberId().equals(memberDO.getId()) && relationDO.getSubRoleId().equals(roleDO.getId()) && relationDO.getRelType().equals(MemberRelationTypeEnum.OTHER.getCode())).collect(Collectors.toList());
        List<Long> upperChannelMemberIds = upperChannelRelationDOList.stream().filter(relationDO -> relationDO.getRole().getMemberType().getTypeEnum().equals(MemberTypeEnum.CHANNEL.getCode()) || relationDO.getRole().getMemberType().getTypeEnum().equals(MemberTypeEnum.CHANNEL_PERSONAL.getCode())).map(MemberRelationDO::getMemberId).distinct().collect(Collectors.toList());

        //上级供应商
        List<MemberAndRoleIdDTO> upperVendorMembers = roleDO.getRoleType().getTypeEnum().equals(RoleTypeEnum.SERVICE_PROVIDER.getCode()) ? relationDOList.stream().filter(relationDO -> relationDO.getSubMemberId().equals(memberDO.getId()) && relationDO.getSubRoleId().equals(roleDO.getId()) && relationDO.getRelType().equals(MemberRelationTypeEnum.OTHER.getCode()) && relationDO.getRole().getRoleType().getTypeEnum().equals(RoleTypeEnum.SERVICE_PROVIDER.getCode())).map(relationDO -> new MemberAndRoleIdDTO(relationDO.getMemberId(), relationDO.getRoleId())).collect(Collectors.toList()) : new ArrayList<>();

        //下级供应商
        List<MemberAndRoleIdDTO> subVendorMembers = roleDO.getRoleType().getTypeEnum().equals(RoleTypeEnum.SERVICE_PROVIDER.getCode()) ? relationDOList.stream().filter(relationDO -> relationDO.getMemberId().equals(memberDO.getId()) && relationDO.getRoleId().equals(roleDO.getId()) && relationDO.getRelType().equals(MemberRelationTypeEnum.OTHER.getCode()) && relationDO.getSubRole().getRoleType().getTypeEnum().equals(RoleTypeEnum.SERVICE_PROVIDER.getCode())).map(relationDO -> new MemberAndRoleIdDTO(relationDO.getSubMemberId(), relationDO.getSubRoleId())).collect(Collectors.toList()) : new ArrayList<>();

        //下级渠道会员的Id列表
        List<MemberRelationDO> subChannelRelationDOList = relationDOList.stream().filter(relationDO -> relationDO.getMemberId().equals(memberDO.getId()) && relationDO.getRoleId().equals(roleDO.getId()) && relationDO.getRelType().equals(MemberRelationTypeEnum.OTHER.getCode())).collect(Collectors.toList());
        List<MemberAndRoleIdDTO> subChannelMembers = subChannelRelationDOList.stream().filter(relationDO -> relationDO.getSubRole().getMemberType().getTypeEnum().equals(MemberTypeEnum.CHANNEL.getCode()) || relationDO.getSubRole().getMemberType().getTypeEnum().equals(MemberTypeEnum.CHANNEL_PERSONAL.getCode())).map(relationDO -> {
            MemberAndRoleIdDTO dto = new MemberAndRoleIdDTO();
            dto.setMemberId(relationDO.getSubMemberId());
            dto.setRoleId(relationDO.getSubRoleId());
            return dto;
        }).collect(Collectors.toList());

        Long siteId = memberCacheService.getLongValueFromRequestHeader(headers, ServiceConfig.USER_LOGIN_SITE_HTTP_HEADERS_KEY);
        Long shopId = memberCacheService.getLongValueFromRequestHeader(headers, ServiceConfig.USER_LOGIN_SHOP_HTTP_HEADERS_KEY);

        //缓存用户信息
        memberCacheService.cacheUserInfo(UserLoginSourceEnum.parseInt(loginUser.getLoginSource()), memberLevelTypeEnum, memberUserDO, memberDO, roleDO, upperChannelMemberIds, upperVendorMembers, subVendorMembers, subChannelMembers, new ArrayList<>(), token, siteId, shopId, level);

        //返回结果
        WebLoginBO webLoginBO = new WebLoginBO(memberUserDO.getId(), memberUserDO.getMember().getId(), token, memberUserDO.getAccount(), memberDO.getName(), memberUserDO.getName(), ServiceVariable.WEB_LOGIN_TOKEN_EXPIRE_MINUTES, urlList, auth, roleDO.getId(), roleDO.getMemberType().getTypeEnum(), roleDO.getRoleType().getTypeEnum(), roleNames, validateStatus, validateStatusDesc, validateMsg, level, levelTag, score, creditPoint, logo, roleItemList);

        //异步： 计算会员登录获得的积分、会员注册年限获得的信用积分
        baseMemberLevelAsyncService.calculateMemberLoginScore(loginPlatformRelationDO, UserLoginSourceEnum.BUSINESS_WEB.getCode());
        baseMemberCreditAsyncService.calculateMemberRegisterYearsCredit(relationDOList.stream().filter(relationDO -> relationDO.getSubMemberId().equals(memberDO.getId()) && relationDO.getSubRoleId().equals(roleDO.getId())).collect(Collectors.toList()));

        //记录最后一次登录时间
        updateUserLastLoginTimeAsync(memberUserDO.getId());

        return Wrapper.success(webLoginBO);
    }

    /**
     * 业务平台 - 重新获取用户信息接口
     *
     * @param headers HttpHeaders信息
     * @return 操作结果
     */
    @Override
    public Wrapper<WebLoginBO> loginBusinessPlatformWithToken(HttpHeaders headers) {
        UserLoginCacheDTO loginUser = memberCacheService.checkUserFromCache(headers);

        //登录来源
        if (!loginUser.getLoginSource().equals(UserLoginSourceEnum.BUSINESS_WEB.getCode())) {
            return Wrapper.fail(ResponseCode.NEED_LOGIN_FROM_BUSINESS_CENTER);
        }

        String token = headers.getFirst(ServiceConfig.USER_TOKEN_HTTP_HEADERS_KEY);

        //从数据库中读取用户信息
        MemberUserDO memberUserDO = memberUserRepository.findById(loginUser.getUserId()).orElse(null);
        if (memberUserDO == null || memberUserDO.getStatus().equals(EnableDisableStatus.DISABLE.getCode())) {
            return Wrapper.fail(ResponseCode.USER_ACCOUNT_OR_PASSWORD_INCORRECT);
        }

        //平台会员关系列表：找出为未冻结的、角色状态为正常的
        Specification<MemberRelationDO> specification = (Specification<MemberRelationDO>) (root, query, criteriaBuilder) -> {
            List<Predicate> list = new ArrayList<>();
            list.add(criteriaBuilder.equal(root.get("relType").as(Integer.class), MemberRelationTypeEnum.PLATFORM.getCode()));
            list.add(criteriaBuilder.equal(root.get("subMemberId").as(Long.class), loginUser.getMemberId()));
            list.add(criteriaBuilder.equal(root.get("status").as(Integer.class), MemberStatusEnum.NORMAL.getCode()));
            Join<Object, Object> subRoleJoin = root.join("subRole", JoinType.LEFT);
            list.add(criteriaBuilder.equal(subRoleJoin.get("status").as(Integer.class), EnableDisableStatus.ENABLE.getCode()));
            Predicate[] p = new Predicate[list.size()];
            return criteriaBuilder.and(list.toArray(p));
        };

        List<MemberRelationDO> relationDOList = relationRepository.findAll(specification);
        if (CollectionUtils.isEmpty(relationDOList)) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_DOES_NOT_EXIST);
        }

        //登录的平台会员关系
        MemberRelationDO platformMemberRelation = relationDOList.stream().filter(r -> r.getSubRoleId().equals(loginUser.getMemberRoleId())).findFirst().orElse(null);
        if (platformMemberRelation == null) {
            return Wrapper.fail(ResponseCode.MC_MS_ROLE_DOES_NOT_EXIST);
        }

        RoleDO roleDO = platformMemberRelation.getSubRole();

        List<WebLoginBO.MemberRoleItem> roleItemList = relationDOList.stream().sorted(Comparator.comparingLong(MemberRelationDO::getSubRoleId)).map(r -> {
            WebLoginBO.MemberRoleItem item = new WebLoginBO.MemberRoleItem();
            item.setMemberRoleId(r.getSubRoleId());
            item.setMemberRoleName(r.getSubRoleName());
            item.setRoleType(r.getSubRole().getRoleType().getTypeEnum());
            return item;
        }).collect(Collectors.toList());

        String companyName = loginUser.getCompany();
        //会员所有角色
        String roleNames = relationDOList.stream().map(relationDO -> relationDO.getSubRole().getRoleName()).collect(Collectors.joining(","));
        //审核状态（如果审核状态为不通过，找到审核不通过的原因）
        Integer validateStatus = platformMemberRelation.getOuterStatus();
        String validateStatusDesc = MemberOuterStatusEnum.getCodeMsg(validateStatus);
        String validateMsg = "";
        if (validateStatus.equals(MemberOuterStatusEnum.PLATFORM_VERIFY_NOT_PASSED.getCode())) {
            validateMsg = StringUtils.hasLength(platformMemberRelation.getValidateMsg()) ? platformMemberRelation.getValidateMsg() : "";
        }

        Integer level = platformMemberRelation.getLevelRight().getLevel();
        String levelTag = platformMemberRelation.getLevelRight().getLevelTag();
        Integer score = platformMemberRelation.getLevelRight().getScore();
        Integer creditPoint = platformMemberRelation.getCredit().getCreditPoint();
        String logo = StringUtils.hasLength(memberUserDO.getLogo()) ? memberUserDO.getLogo() : "";

        //授权访问的前菜单Code列表
        //List<String> urlList = platformMemberRelation.getVerified().equals(MemberValidateStatusEnum.VERIFY_PASSED.getCode()) ? AuthBOUtils.getAccessUrlList(memberUserDO.getUserAuth().getAuth(), platformMemberRelation.getRelationAuth().getAuth(), UserLoginSourceEnum.BUSINESS_WEB.getCode(), ServiceConfig.MEMBER_MAIN_WEB_PAGE_CODES) : ServiceConfig.MEMBER_MAIN_WEB_PAGE_CODES;
        List<String> urlList = new ArrayList<>();
        List<LoginAuthBO> auth = AuthBOUtils.getAccessAuth(platformMemberRelation.getVerified().equals(MemberValidateStatusEnum.VERIFY_PASSED.getCode()), memberUserDO.getUserAuth().getAuth(), platformMemberRelation.getRelationAuth().getAuth(), UserLoginSourceEnum.BUSINESS_WEB.getCode(), ServiceConfig.MEMBER_MAIN_WEB_PAGE_CODES);

        //返回结果
        WebLoginBO webLoginBO = new WebLoginBO(memberUserDO.getId(), memberUserDO.getMember().getId(), token, memberUserDO.getAccount(), companyName, memberUserDO.getName(), ServiceVariable.WEB_LOGIN_TOKEN_EXPIRE_MINUTES, urlList, auth, roleDO.getId(), roleDO.getMemberType().getTypeEnum(), roleDO.getRoleType().getTypeEnum(), roleNames, validateStatus, validateStatusDesc, validateMsg, level, levelTag, score, creditPoint, logo, roleItemList);
        return Wrapper.success(webLoginBO);
    }


    /**
     * 平台后台 - 账号密码登录
     *
     * @param headers HttpHeaders信息
     * @param loginVO 接口参数
     * @return 操作结果
     */
    @Override
    public Wrapper<ManageLoginBO> manageAccountOrPhoneLogin(HttpHeaders headers, ManageLoginVO loginVO) {
        memberCacheService.checkPlatformRequestHeader(headers);

        //从会员关联的用户中获取用户信息
        MemberDO memberDO = memberRepository.findFirstByAccount(ServiceConfig.PLATFORM_SUPER_ADMIN_ACCOUNT);
        if (memberDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_DOES_NOT_EXIST);
        }

        //如果不是平台后台账号，不允许登录管理平台
        RoleDO roleDO = memberDO.getRoles().stream().findFirst().orElse(null);
        if (roleDO == null || !roleDO.getRelType().equals(MemberRelationTypeEnum.PLATFORM.getCode())) {
            return Wrapper.fail(ResponseCode.MC_MS_NEED_LOGIN_WITH_PLATFORM_ROLE);
        }

        if (CollectionUtils.isEmpty(memberDO.getUsers())) {
            return Wrapper.fail(ResponseCode.USER_ACCOUNT_OR_PASSWORD_INCORRECT);
        }

        MemberUserDO memberUserDO = memberDO.getUsers().stream().filter(user -> user.getAccount().equals(loginVO.getAccount()) && user.getStatus().equals(EnableDisableStatus.ENABLE.getCode())).findFirst().orElse(null);
        if (memberUserDO == null || memberUserDO.getStatus().equals(EnableDisableStatus.DISABLE.getCode())) {
            return Wrapper.fail(ResponseCode.USER_ACCOUNT_OR_PASSWORD_INCORRECT);
        }

        //校验密码，生成token
        if (!PasswordUtil.instance().checkPassword(memberUserDO.getPassword(), loginVO.getPassword())) {
            return Wrapper.fail(ResponseCode.USER_ACCOUNT_OR_PASSWORD_INCORRECT);
        }

        String token = TokenUtil.instance().getToken();

        //记录最后一次登录时间
        updateUserLastLoginTimeAsync(memberUserDO.getId());

        Long siteId = memberCacheService.getLongValueFromRequestHeader(headers, ServiceConfig.USER_LOGIN_SITE_HTTP_HEADERS_KEY);
        Long shopId = memberCacheService.getLongValueFromRequestHeader(headers, ServiceConfig.USER_LOGIN_SHOP_HTTP_HEADERS_KEY);

        //缓存用户信息
        memberCacheService.cacheUserInfo(UserLoginSourceEnum.BUSINESS_MANAGEMENT_PLATFORM, MemberLevelTypeEnum.PLATFORM.getCode(), memberUserDO, memberDO, roleDO, new ArrayList<>(), new ArrayList<>(), new ArrayList<>(), new ArrayList<>(), new ArrayList<>(), token, siteId, shopId,null);

        //用户的前端url权限
        List<String> urlList = CollectionUtils.isEmpty(memberUserDO.getUserAuth().getAuth()) ? new ArrayList<>() : memberUserDO.getUserAuth().getAuth().stream().filter(authBO -> authBO.getSource().equals(UserLoginSourceEnum.BUSINESS_MANAGEMENT_PLATFORM.getCode())).map(AuthBO::getUrl).collect(Collectors.toList());
        //List<LoginAuthBO> auth = CollectionUtils.isEmpty(memberUserDO.getUserAuth().getAuth()) ? new ArrayList<>() : memberUserDO.getUserAuth().getAuth().stream().filter(authBO -> authBO.getSource().equals(UserLoginSourceEnum.BUSINESS_MANAGEMENT_PLATFORM.getCode())).map(authBO -> new LoginAuthBO(authBO.getUrl(), authBO.getButtons().stream().map(ButtonBO::getUrl).collect(Collectors.toList()))).collect(Collectors.toList());
        List<LoginAuthBO> auth = new ArrayList<>();

        //返回结果
        ManageLoginBO loginBO = new ManageLoginBO(memberUserDO.getId(), memberUserDO.getMember().getId(), roleDO.getId(), token, memberUserDO.getAccount(), memberUserDO.getName(), ServiceVariable.WEB_LOGIN_TOKEN_EXPIRE_MINUTES, urlList, auth);
        return Wrapper.success(loginBO);
    }

    /**
     * 平台后台 - 重新获取用户信息接口
     *
     * @param headers HttpHeaders信息
     * @return 操作结果
     */
    @Override
    public Wrapper<ManageLoginBO> loginManagePlatformWithToken(HttpHeaders headers) {
        UserLoginCacheDTO loginUser = memberCacheService.checkUserFromCache(headers);

        //登录来源
        if (!loginUser.getLoginSource().equals(UserLoginSourceEnum.BUSINESS_MANAGEMENT_PLATFORM.getCode())) {
            return Wrapper.fail(ResponseCode.NEED_LOGIN_FROM_MANAGE_PLATFORM);
        }

        String token = headers.getFirst(ServiceConfig.USER_TOKEN_HTTP_HEADERS_KEY);

        //从数据库中读取用户信息
        MemberUserDO memberUserDO = memberUserRepository.findById(loginUser.getUserId()).orElse(null);
        if (memberUserDO == null || memberUserDO.getStatus().equals(EnableDisableStatus.DISABLE.getCode())) {
            return Wrapper.fail(ResponseCode.USER_ACCOUNT_OR_PASSWORD_INCORRECT);
        }

        MemberDO memberDO = memberUserDO.getMember();
        if (memberDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_DOES_NOT_EXIST);
        }

        //如果不是平台后台账号，不允许登录管理平台
        RoleDO roleDO = memberDO.getRoles().stream().findFirst().orElse(null);
        if (roleDO == null || !roleDO.getRelType().equals(MemberRelationTypeEnum.PLATFORM.getCode())) {
            return Wrapper.fail(ResponseCode.MC_MS_NEED_LOGIN_WITH_PLATFORM_ROLE);
        }

        //用户的前端url权限
        List<String> urlList = CollectionUtils.isEmpty(memberUserDO.getUserAuth().getAuth()) ? new ArrayList<>() : memberUserDO.getUserAuth().getAuth().stream().filter(authBO -> authBO.getSource().equals(UserLoginSourceEnum.BUSINESS_MANAGEMENT_PLATFORM.getCode())).map(AuthBO::getUrl).collect(Collectors.toList());
        //List<LoginAuthBO> auth = CollectionUtils.isEmpty(memberUserDO.getUserAuth().getAuth()) ? new ArrayList<>() : memberUserDO.getUserAuth().getAuth().stream().filter(authBO -> authBO.getSource().equals(UserLoginSourceEnum.BUSINESS_MANAGEMENT_PLATFORM.getCode())).map(authBO -> new LoginAuthBO(authBO.getUrl(), authBO.getButtons().stream().map(ButtonBO::getUrl).collect(Collectors.toList()))).collect(Collectors.toList());
        List<LoginAuthBO> auth = new ArrayList<>();

        //返回结果
        ManageLoginBO loginBO = new ManageLoginBO(memberUserDO.getId(), memberUserDO.getMember().getId(), roleDO.getId(), token, memberUserDO.getAccount(), memberUserDO.getName(), ServiceVariable.WEB_LOGIN_TOKEN_EXPIRE_MINUTES, urlList, auth);
        return Wrapper.success(loginBO);
    }

    /**
     * 更新用户最后一次登录时间
     *
     * @param userId 用户Id
     */
    @Async
    public void updateUserLastLoginTimeAsync(Long userId) {
        String sql = String.format("update ms_mc_member_user set last_login_time = '%s' where id = %d", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")), userId);
        jdbcTemplate.update(sql);
    }

    @Override
    public Wrapper<MemberAuthCodeVO> getAuthLoginUrl(HttpHeaders headers) {
        // 校验web登录
        memberCacheService.checkWebRequestHeader(headers);

        // 生成授权码
        AuthCodeBO authCodeBO = memberCacheService.createAuthCode();

        // 授权url
        String authUrl = ServiceVariable.AUTH_URL + Constants.LOGIN_QR_AUTH_ACTION + StrUtil.format(ServiceConfig.QR_CODE_SIGN_TEMPLATE, authCodeBO.getAuthCode());

        MemberAuthCodeVO memberAuthCodeVO = new MemberAuthCodeVO();
        memberAuthCodeVO.setAuthUrl(authUrl);
        memberAuthCodeVO.setExpireTime(authCodeBO.getExpire());
        return Wrapper.success(memberAuthCodeVO);
    }

    @Override
    public Wrapper<WebLoginBO> getAuthCodeLoginInfo(HttpHeaders headers, ActivityMemberAuthCodeVO memberAuthCodeVO) {
        // 获取缓存的登录信息
        AuthCodeMemberBO authCodeMemberBO = memberCacheService.getAuthDetail(memberAuthCodeVO.getAuthCode());
        if (Objects.isNull(authCodeMemberBO)) {
            return Wrapper.fail(ResponseCode.MC_MS_APP_LOGIN_AUTH_CODE_ERROR);
        }

        MemberDO memberDO = memberRepository.findById(authCodeMemberBO.getMemberId()).orElse(null);
        if (memberDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_DOES_NOT_EXIST);
        }


        MemberUserDO memberUserDO = memberUserRepository.findById(authCodeMemberBO.getUserId()).orElse(null);
        if (memberUserDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_DOES_NOT_EXIST);
        }

        //登录会员上下级会员的关系列表
        Specification<MemberRelationDO> specification = (Specification<MemberRelationDO>) (root, query, criteriaBuilder) -> {
            List<Predicate> list = new ArrayList<>();
            Predicate memberIdEqual = criteriaBuilder.equal(root.get("memberId").as(Long.class), memberDO.getId());
            Predicate subMemberIdEqual = criteriaBuilder.equal(root.get("subMemberId").as(Long.class), memberDO.getId());
            list.add(criteriaBuilder.or(memberIdEqual, subMemberIdEqual));
            Predicate[] p = new Predicate[list.size()];
            return criteriaBuilder.and(list.toArray(p));
        };

        List<MemberRelationDO> relationDOList = relationRepository.findAll(specification);
        if (CollectionUtils.isEmpty(relationDOList)) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_DOES_NOT_EXIST);
        }

        //从“平台会员”关系中，查询是否已经被冻结
        List<MemberRelationDO> platformRelationDOList = relationDOList.stream().filter(relationDO -> relationDO.getSubMemberId().equals(memberDO.getId()) && relationDO.getRelType().equals(MemberRelationTypeEnum.PLATFORM.getCode())).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(platformRelationDOList)) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_DOES_NOT_EXIST);
        }

        //如果所有平台关系已经被冻结，返回
        List<Long> unfrozenRoleIdList = platformRelationDOList.stream().filter(relationDO -> relationDO.getStatus().equals(MemberStatusEnum.NORMAL.getCode())).map(MemberRelationDO::getSubRoleId).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(unfrozenRoleIdList)) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_HAS_BEEN_FROZEN);
        }

        //筛选出未冻结、状态为启用的角色
        List<RoleDO> availableRoles = memberDO.getRoles().stream().filter(roleDO -> roleDO.getStatus().equals(EnableDisableStatus.ENABLE.getCode()) && unfrozenRoleIdList.contains(roleDO.getId())).sorted(Comparator.comparingLong(RoleDO::getId)).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(availableRoles)) {
            return Wrapper.fail(ResponseCode.MC_MS_ROLE_HAS_BEEN_DISABLED);
        }

        //会员所有角色
        String roleNames = availableRoles.stream().map(RoleDO::getRoleName).collect(Collectors.joining(","));

        //登录的角色
        RoleDO roleDO = availableRoles.get(0);
        List<WebLoginBO.MemberRoleItem> roleItemList = availableRoles.stream().map(r -> {
            WebLoginBO.MemberRoleItem item = new WebLoginBO.MemberRoleItem();
            item.setMemberRoleId(r.getId());
            item.setMemberRoleName(r.getRoleName());
            item.setRoleType(r.getRoleType().getTypeEnum());
            return item;
        }).collect(Collectors.toList());

        //登录的平台会员关系
        MemberRelationDO loginPlatformRelationDO = relationDOList.stream().filter(relationDO -> relationDO.getSubMemberId().equals(memberDO.getId()) && relationDO.getSubRoleId().equals(roleDO.getId()) && relationDO.getRelType().equals(MemberRelationTypeEnum.PLATFORM.getCode())).findFirst().orElse(null);
        if (loginPlatformRelationDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_RELATION_DOES_NOT_EXIST);
        }

        //审核状态（如果审核状态为不通过，找到审核不通过的原因）
        Integer validateStatus = loginPlatformRelationDO.getOuterStatus();
        String validateStatusDesc = MemberOuterStatusEnum.getCodeMsg(validateStatus);
        String validateMsg = "";
        if (validateStatus.equals(MemberOuterStatusEnum.PLATFORM_VERIFY_NOT_PASSED.getCode())) {
            validateMsg = StringUtils.hasLength(loginPlatformRelationDO.getValidateMsg()) ? loginPlatformRelationDO.getValidateMsg() : "";
        }

        Integer level = loginPlatformRelationDO.getLevelRight().getLevel();
        String levelTag = loginPlatformRelationDO.getLevelRight().getLevelTag();
        Integer score = loginPlatformRelationDO.getLevelRight().getScore();
        Integer creditPoint = loginPlatformRelationDO.getCredit().getCreditPoint();
        String logo = StringUtils.hasLength(memberUserDO.getLogo()) ? memberUserDO.getLogo() : "";

        String token;
        try {
            token = TokenUtil.instance().getToken();
        } catch (Exception e) {
            return Wrapper.fail(ResponseCode.SERVICE_ERROR);
        }

        //授权访问的前端菜单Url列表，如果审核没通过，只能访问首页
        //List<String> urlList = validateStatus.equals(MemberOuterStatusEnum.PLATFORM_VERIFY_PASSED.getCode()) ? AuthBOUtils.getAccessUrlList(memberUserDO.getUserAuth().getAuth(), loginPlatformRelationDO.getRelationAuth().getAuth(), UserLoginSourceEnum.BUSINESS_WEB.getCode(), ServiceConfig.MEMBER_MAIN_WEB_PAGE_CODES) : ServiceConfig.MEMBER_MAIN_WEB_PAGE_CODES;
        List<String> urlList = new ArrayList<>();
        List<LoginAuthBO> auth = AuthBOUtils.getAccessAuth(validateStatus.equals(MemberOuterStatusEnum.PLATFORM_VERIFY_PASSED.getCode()), memberUserDO.getUserAuth().getAuth(), loginPlatformRelationDO.getRelationAuth().getAuth(), UserLoginSourceEnum.BUSINESS_WEB.getCode(), ServiceConfig.MEMBER_MAIN_WEB_PAGE_CODES);

        //上级渠道会员的Id列表
        List<Long> upperChannelMemberIds = relationDOList.stream().filter(relationDO -> relationDO.getSubMemberId().equals(memberDO.getId()) && relationDO.getSubRoleId().equals(roleDO.getId()) && relationDO.getRelType().equals(MemberRelationTypeEnum.OTHER.getCode()) && relationDO.getRole().getMemberType().getTypeEnum().equals(MemberTypeEnum.CHANNEL.getCode()) || relationDO.getRole().getMemberType().getTypeEnum().equals(MemberTypeEnum.CHANNEL_PERSONAL.getCode())).map(MemberRelationDO::getMemberId).distinct().collect(Collectors.toList());

        //上级供应商
        List<MemberAndRoleIdDTO> upperVendorMembers = roleDO.getRoleType().getTypeEnum().equals(RoleTypeEnum.SERVICE_PROVIDER.getCode()) ? relationDOList.stream().filter(relationDO -> relationDO.getSubMemberId().equals(memberDO.getId()) && relationDO.getSubRoleId().equals(roleDO.getId()) && relationDO.getRelType().equals(MemberRelationTypeEnum.OTHER.getCode()) && relationDO.getRole().getRoleType().getTypeEnum().equals(RoleTypeEnum.SERVICE_PROVIDER.getCode())).map(relationDO -> new MemberAndRoleIdDTO(relationDO.getMemberId(), relationDO.getRoleId())).collect(Collectors.toList()) : new ArrayList<>();

        //下级供应商
        List<MemberAndRoleIdDTO> subVendorMembers = roleDO.getRoleType().getTypeEnum().equals(RoleTypeEnum.SERVICE_PROVIDER.getCode()) ? relationDOList.stream().filter(relationDO -> relationDO.getMemberId().equals(memberDO.getId()) && relationDO.getRoleId().equals(roleDO.getId()) && relationDO.getRelType().equals(MemberRelationTypeEnum.OTHER.getCode()) && relationDO.getSubRole().getRoleType().getTypeEnum().equals(RoleTypeEnum.SERVICE_PROVIDER.getCode())).map(relationDO -> new MemberAndRoleIdDTO(relationDO.getSubMemberId(), relationDO.getSubRoleId())).collect(Collectors.toList()) : new ArrayList<>();

        //下级渠道会员Id和角色Id列表
        List<MemberRelationDO> subChannelRelationDOList = relationDOList.stream().filter(relationDO -> relationDO.getMemberId().equals(memberDO.getId()) && relationDO.getRoleId().equals(roleDO.getId()) && relationDO.getRelType().equals(MemberRelationTypeEnum.OTHER.getCode())).collect(Collectors.toList());
        List<MemberAndRoleIdDTO> subChannelMembers = subChannelRelationDOList.stream().filter(relationDO -> relationDO.getSubRole().getMemberType().getTypeEnum().equals(MemberTypeEnum.CHANNEL.getCode()) || relationDO.getSubRole().getMemberType().getTypeEnum().equals(MemberTypeEnum.CHANNEL_PERSONAL.getCode())).map(relationDO -> new MemberAndRoleIdDTO(relationDO.getSubMemberId(), relationDO.getSubRoleId())).collect(Collectors.toList());

        // 根据当前登录角色判断等级类型
        Integer memberLevelTypeEnum = MemberLevelTypeEnum.getCodeByMemberType(roleDO.getMemberType().getTypeEnum());

        Long siteId = memberCacheService.getLongValueFromRequestHeader(headers, ServiceConfig.USER_LOGIN_SITE_HTTP_HEADERS_KEY);
        Long shopId = memberCacheService.getLongValueFromRequestHeader(headers, ServiceConfig.USER_LOGIN_SHOP_HTTP_HEADERS_KEY);

        //缓存用户信息
        memberCacheService.cacheUserInfo(UserLoginSourceEnum.BUSINESS_WEB, memberLevelTypeEnum, memberUserDO, memberDO, roleDO, upperChannelMemberIds, upperVendorMembers, subVendorMembers, subChannelMembers, new ArrayList<>(), token, siteId, shopId, level);

        //返回结果
        WebLoginBO webLoginBO = new WebLoginBO(memberUserDO.getId(), memberDO.getId(), token, memberUserDO.getAccount(), memberDO.getName(), memberUserDO.getName(), ServiceVariable.WEB_LOGIN_TOKEN_EXPIRE_MINUTES, urlList, auth, roleDO.getId(), roleDO.getMemberType().getTypeEnum(), roleDO.getRoleType().getTypeEnum(), roleNames, validateStatus, validateStatusDesc, validateMsg, level, levelTag, score, creditPoint, logo, roleItemList);

        //异步： 计算会员登录获得的积分、会员注册年限获得的信用积分
        baseMemberLevelAsyncService.calculateMemberLoginScore(loginPlatformRelationDO, UserLoginSourceEnum.BUSINESS_WEB.getCode());

        baseMemberCreditAsyncService.calculateMemberRegisterYearsCredit(relationDOList.stream().filter(relationDO -> relationDO.getSubMemberId().equals(memberDO.getId()) && relationDO.getSubRoleId().equals(roleDO.getId())).collect(Collectors.toList()));

        //记录最后一次登录时间
        updateUserLastLoginTimeAsync(memberUserDO.getId());

        return Wrapper.success(webLoginBO);
    }

    @Override
    public Wrapper<CaptchaPicVO> captcha(HttpHeaders headers, CaptchaVO captchaVO){
        try {
            // 根据模板裁剪图片
            CaptchaPicVO picVO = VerifyImageUtil.pictureTemplatesCut(captchaVO.getWidth(), captchaVO.getHeight(), captchaVO.getSize());
            // 生成流水号，这里就使用时间戳代替
            String imgId = VerifyImageUtil.getImgId();
            //入缓存
            redisUtils.set(ServiceConfig.MEMBER_REGISTER_CAPTCHA_IMG_REDIS_KEY_PREFIX + imgId, String.valueOf(picVO.getWidth()), 60L, Constants.REDIS_USER_INDEX);
            picVO.setImgId(imgId);
            return Wrapper.success(picVO);
        } catch (Exception e) {
            return Wrapper.fail(ResponseCode.SERVICE_ERROR, e.getMessage());
        }
    }
}
